<!--
 * @Author: zhangyang
 * @Date: 2022-03-01 20:04:26
 * @LastEditTime: 2022-06-26 16:19:06
 * @Description: 角色列表
-->
<script lang="ts" setup>
import useFormMode from '@/hooks/useFormMode';
import { NButton, NSpace, NSwitch } from 'naive-ui';
import type { TableDataItem, TableHeadItemPro } from '@/typings/table';
import type { RoleItem, NavArrItem, BaseQuery, ApiItem } from '@/typings';
import { expandNodeKeys } from '@/stores';
import { addRoleItem, changeRoleApi, changeRoleItem, changeRoleMenu, deleteRole, getRoleList } from '@/api/role';
import { getRoleMenuTree } from '@/api/menu';
import { getRoleApis } from '@/api/api';

const FORM_TEMP: RoleItem = {
  id: 0,
  name: '',
  keyword: '',
  desc: '',
  status: 1,
  sort: 0
};

const {
  isAdd,
  isEdit,
  edit,
  del,
  sure,
  clear,
  form,
  formRef,
  // @ts-ignore
  validForm
} = useFormMode(FORM_TEMP, {
  // @ts-ignore
  addCbk: async () => {
    const res: boolean = await validForm();
    if (res) {
      const v = deepClone(form.value);
      clear();
      await addRoleItem(v);
      window.$message.success('新增成功！');
    }
    return res;
  },
  // @ts-ignore
  modCbk: async () => {
    const res: boolean = await validForm();
    if (res) {
      const v = deepClone(form.value);
      clear();
      await changeRoleItem(v);
      window.$message.success('修改成功！');
    }
    return res;
  },
  delCbk: async (row) => {
    await deleteRole(row.id.toString());
    window.$message.success('删除成功！');
    query.pageNum = 1;
  },
  cgEffect: () => getList()
});
const currRole = ref(0);

const tableHeadMenu: TableHeadItemPro<NavArrItem>[] = [
  { type: 'selection' },
  { key: 'name', title: '菜单名称' },
  { key: 'id', title: '菜单ID' },
  { key: 'parentId', title: '父节点' },
  { key: 'component', title: '页面路径' },
  { key: 'visible', title: '隐藏/显示', render: (row) => h(NSwitch, {
      checkedValue: 1,
      uncheckedValue: 0,
      value: row.visible,
      disabled: true
    })
  },
];
const tableDataMenu = ref<TableDataItem<NavArrItem>[]>([]);
const showPriority =ref(false);
const accessNodes = ref<number[]>([]);
const originNodes = ref<number[]>([]);
const editP = async (row: TableDataItem<RoleItem>) => {
  currRole.value = row.id;
  const { list, accessIds } = await getRoleMenuTree(row.id);
  tableDataMenu.value = deepClone(list);
  accessNodes.value = accessIds;
  originNodes.value = accessIds;
  showPriority.value = true;
};
const clearP = () => {
  showPriority.value = false;
  currRole.value = 0;
  tableDataMenu.value.length = 0;
};
const sureP = async () => {
  const before = originNodes.value.slice();
  const now = accessNodes.value.slice();

  const add = now.filter((v) => !before.includes(v));
  const del = before.filter((v) => !now.includes(v));

  await changeRoleMenu(currRole.value, add, del);
  window.$message.success('修改成功！');
  clearP();
};

const tableHeadApi: TableHeadItemPro<ApiItem>[] = [
  { type: 'selection' },
  { key: 'desc', title: '接口描述' },
  { key: 'id', title: '接口ID' },
  { key: 'method', title: '接口方法' },
  { key: 'path', title: '请求地址' },
];
const tableDataApi = ref<TableDataItem<ApiItem>[]>([]);
const showAPi =ref(false);
const accessApis = ref<number[]>([]);
const originApis = ref<number[]>([]);
const editA = async (row: TableDataItem<RoleItem>) => {
  currRole.value = row.id;
  const { list, accessIds } = await getRoleApis(row.id);
  tableDataApi.value = deepClone(list);
  accessApis.value = accessIds;
  originApis.value = accessIds;
  showAPi.value = true;
};
const clearA = () => {
  showAPi.value = false;
  currRole.value = 0;
  tableDataApi.value.length = 0;
};
const sureA = async () => {
  const before = originApis.value.slice();
  const now = accessApis.value.slice();

  const add = now.filter((v) => !before.includes(v));
  const del = before.filter((v) => !now.includes(v));

  await changeRoleApi(currRole.value, add, del);
  window.$message.success('修改成功！');
  clearA();
};

const renderOperate = (row: TableDataItem<RoleItem>) => {
  return h(NSpace, {}, {
    default: () => [
      h(
        NButton,
        { size: 'small', onClick: () => edit(row) },
        { default: () => '信息编辑' }
      ),
      h(
        NButton,
        { type: 'info', size: 'small', ghost: true, onClick: () => editP(row) },
        { default: () => '菜单编辑' }
      ),
      h(
        NButton,
        { type: 'info', size: 'small', ghost: true, onClick: () => editA(row) },
        { default: () => '接口编辑' }
      ),
      h(
        NButton,
        { type: 'error', size: 'small', ghost: true, onClick: () => del(row) },
        { default: () => '删除' }
      ),
    ]
  })
};
const tableHead: TableHeadItemPro<RoleItem>[] = [
  { key: 'id', title: '角色ID' },
  { key: 'name', title: '角色名称' },
  { key: 'desc', title: '角色描述' },
  { key: 'creator', title: '创建信息' },
  { key: 'status', title: '禁用/启用', render: (row) => h(NSwitch, {
      size: 'small', 
      checkedValue: 1,
      uncheckedValue: 0,
      value: row.status,
      onUpdateValue: async (status) => {
        await changeRoleItem({ id: row.id, status });
        window.$message.success('修改成功！');
        getList();
      }
    })
  },
  { key: 'id', title: '操作', render: renderOperate, width: '380' }
];
const tableData = ref<TableDataItem<RoleItem>[]>([]);


interface Query extends BaseQuery {
  name: string;
  keyword: string;
  status: 0 | 1;
};
const query = reactive<Query>({
  pageNum: 1,
  pageSize: 50,
  total: 0,
  name: '',
  keyword: '',
  status: 1
});

const getList = async () => {
  const { list, pageNum, pageSize, total } = await getRoleList(query);
  tableData.value = deepClone(list || []);
  query.pageNum = pageNum;
  query.pageSize = pageSize;
  query.total = total;
};

getList();
</script>

<route lang="yaml">
meta:
  title: 角色列表
  authPath: /system/role
</route>

<template>
  <div class="flex">
    <div class="m-2">
      <NInput v-model:value="query.name" placeholder="请输入角色名称(中文)" />
    </div>
    <div class="m-2">
      <NInput v-model:value="query.keyword" placeholder="请输入角色关键字(英文)" />
    </div>
    <div class="m-2 w-50">
      <NSelect
        v-model:value="query.status"
        placeholder="请选择状态"
        clearable
        :options="[
          { label: '1-启用', value: 1 },
          { label: '0-禁用', value: 0 },
        ]"
      />
    </div>
    <div class="m-2">
      <NButton type="info" ghost @click="getList">搜索</NButton>
    </div>
    <div class="m-2">
      <NButton type="success" ghost @click="isAdd=true">添加角色</NButton>
    </div>
  </div>
  <div class="m-2">
    <YoungTablePro
      v-model:page="query.pageNum"
      v-model:limit="query.pageSize"
      :total="query.total"
      :table-data="tableData"
      :table-head="tableHead"
      @page-change="getList"
    />
  </div>
  <!-- 基础信息编辑 -->
  <YoungDialog
    :is-add="isAdd"
    :is-edit="isEdit"
    @sure="sure"
    @clear="clear"
  >
    <template #body>
      <NForm
        ref="formRef"
        :model="form"
        label-placement="left"
        label-width="120"
      >
        <NFormItem
          label="角色名称(中文)"
          path="name"
          :rule="[{ required: true, message: '请填写角色名称', trigger: 'blur' }]"
        >
          <NInput v-model:value="form.name" />
        </NFormItem>
        <NFormItem
          label="关键字(英文)"
          path="keyword"
          :rule="[{ required: true, message: '请填写关键字', trigger: 'blur' }]"
        >
          <NInput v-model:value="form.keyword" />
        </NFormItem>
        <NFormItem label="角色描述">
          <NInput v-model:value="form.desc" />
        </NFormItem>
      </NForm>
    </template>
  </YoungDialog>
  <!-- 菜单编辑 -->
  <YoungDialog
    real-title="菜单编辑"
    :is-edit="showPriority"
    style="width: 80vw; top: 5vh;"
    @sure="sureP"
    @clear="clearP"
  >
    <template #body>
      <YoungTablePro
        :table-data="tableDataMenu"
        :table-head="tableHeadMenu"
        :row-key="(item: RoleItem) => item.id"
        v-model:checked-row-keys="accessNodes"
        :cascade="false"
        :max-height="600"
        v-model:expanded-row-keys="expandNodeKeys"
      />
    </template>
  </YoungDialog>
  <!-- 接口编辑 -->
  <YoungDialog
    real-title="接口编辑"
    :is-edit="showAPi"
    style="width: 80vw; top: 5vh;"
    @sure="sureA"
    @clear="clearA"
  >
    <template #body>
      <YoungTablePro
        :table-data="tableDataApi"
        :table-head="tableHeadApi"
        :row-key="(item: ApiItem) => item.id"
        v-model:checked-row-keys="accessApis"
        :cascade="false"
        :max-height="600"
      />
    </template>
  </YoungDialog>
</template>